Longest Palindromic Substring

Given a string S, find the longest palindromic substring in S.
You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.

题目大意:寻找给定字符串(长度不超过1000)的最长回文子串,回文子串存在且唯一

题目难度:Medium

/**
 * Created by gzdaijie on 16/5/3
 * 回文字符串只有2种形式, abba,aba
 * (1) 遍历字符,查看其左右是否相等, 更新start,end
 * (2) 遍历字符,如果右边与当前字符相等,查看这2个字符的左右是否相等, 更新start,end
 * 若最长回文串长度为K,最坏复杂度为O(K*N)
 */
public class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        int start = 0, end =  0;

        for (int i = 0; i < len; ++i) {
            // 情况1: aba,奇数回文串
            int k = 1;
            while (i - k >= 0 && i + k < len && s.charAt(i - k) == s.charAt(i + k)) ++k;
            if (end - start < 2 * k - 1) {
                start = i - k + 1;
                end = i + k;
            }
            // 情况2: abba,偶数回文串
            k = 0;
            while (i - k >= 0 && i + k + 1 < len && s.charAt(i - k) == s.charAt(i + k + 1)) ++k;
            if (end - start < 2 * k) {
                start = i - k + 1;
                end = i + k + 1;
            }
        }
        return s.substring(start, end);
    }
}
/**
 * Created by gzdaijie on 16/5/3
 * 首先所有字符都相同的字符串无论字符多少,都是回文字符串
 * 对于有连续相等的字符的字符串, zxyyyyyyxa,只需找到连续相等的y的第一个和最后一个位置,判断左右即可
 * 遍历时,可直接从第一个y的位置跳到最后一个y下一位
 * 当字符有1000个,连续出现同一字符概率很大,因此此算法非常高效,但是若无连续出现字符,仍为O(N*K)
 */
public class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        int max = 0;
        int start = 0;
        int end = 0;

        for (int i = 0; i < len;) {
            int index = this.getFarestSameChar(s, i);
            int dist = this.getDistance(s,i ,index);
            int p = i - dist;
            int q = index + dist;
            if (q - p + 1 > max) {
                start = p;
                end = q;
                max = end - start + 1;
            }
            i = index + 1; // 从i->index的字符都是相等的,因此可以直接跳过
        }
        return s.substring(start, end + 1);

    }

    /**
     * 判断左右是回文字符的个数
     */
    private int getDistance(String s, int start, int end) {
        int len = s.length();
        int dist = 0;

        start -= 1;
        end += 1;
        while (start >= 0 && end < len) {
            if (s.charAt(start) != s.charAt(end)) break;
            --start;
            ++end;
            ++dist;
        }
        return dist;
    }

    /**
     * 连续字符,最远的一个下标
     */
    private int getFarestSameChar(String s, int index) {
        int len = s.length();
        char ch = s.charAt(index);
        for (int i = index + 1; i < len; ++i) {
            if (ch != s.charAt(i))return i - 1;
        }
        return len - 1;
    }
}
/**
 * Created by gzdaijie on 16/5/4
 * Manacher 算法
 * 使用#扩展字符串解决奇偶回文字符串问题
 * 使用数组RL和对称中心pos,避免重复计算
 * 复杂度O(N),分析见参考
 * 但是在leetcode上运行时间超过以上2种,原因未知
 */
public class Solution {
    public String longestPalindrome(String s) {
        String str = this.addSharpToString(s);

        int len = str.length();
        int max, start, end;
        int maxRight, pos;
        int[] RL = new int[len];

        max = start = end = maxRight = pos = 0;
        for (int i = 0; i < len; ++i) {
            // 如果i在maxRight的左边,初始值设置为i的对称位的值
            if (i < maxRight) {
                RL[i] = Math.min(RL[2 * pos - i], maxRight - i + 1);
            } else {
                RL[i] = 1;
            }
            // 尝试对i进行扩展
            while (i - RL[i] >= 0 && i + RL[i] < len) {
                if (str.charAt(i - RL[i]) != str.charAt(i + RL[i])) break;
                RL[i]++;
            }
            // 更新最大右边界与对称中心
            if (i + RL[i] - 1 > maxRight) {
                maxRight = RL[i] + i - 1;
                pos = i;
            }
            // 更新 max与首末位置
            if (RL[i] > max) {
                max = RL[i];
                start = i- RL[i] + 1;
                end = i + RL[i] - 1;
            }
        }
        // 去掉#,连接字符串并返回
        String result = "";
        String[] strings = str.substring(start, end + 1).split("#");
        len = strings.length;
        for (int i = 0; i < len; i++) {
            result += strings[i];
        }
        return result;
    }
    private String addSharpToString(String s) {
        int len = s.length();
        String str = "#";
        for (int i = 0; i < len; ++i) {
            str += s.charAt(i) + "#";
        }
        return str;
    }
}

参考:最长回文子串——Manacher 算法

gzdaijie            updated 2016-05-04 01:26:48

results matching ""

    No results matching ""